package ioc

import (
	"log"
	"reflect"
	"sync"
)

type Bean interface {
	PostConstructor() any
	BeanName() string
	Type() reflect.Type
}

type BeanFactory struct {
	container     map[string][]any
	typeContainer map[reflect.Type]any
	lock          sync.Mutex
}

func NewBeanFactory() *BeanFactory {
	return &BeanFactory{
		container:     make(map[string][]any),
		typeContainer: make(map[reflect.Type]any),
	}
}

func (b *BeanFactory) ContainerInit(beans []Bean) {
	for _, bean := range beans {
		value := bean.PostConstructor()
		if values, ok := b.container[bean.BeanName()]; ok {
			b.container[bean.BeanName()] = append(values, value)
		} else {
			anies := make([]any, 0)
			anies = append(anies, value)
			b.container[bean.BeanName()] = anies
		}
		b.typeContainer[bean.Type()] = value
		//log.Println(bean.Type())
	}
	//遍历bean容器
	for name, beans := range b.container {
		//使用反射获取bean的值引用与类型引用
		for _, bean := range beans {
			valueOf := reflect.ValueOf(bean)
			typeOf := valueOf.Elem().Type()
			//遍历bean的属性,根据tag从容器中 获取对应对象进行注入
			for i := 0; i < typeOf.NumField(); i++ {
				field := typeOf.Field(i)
				if beanName, ok := field.Tag.Lookup("bean"); ok {
					if diBean, ok := b.typeContainer[field.Type]; ok && diBean != nil {
						of := reflect.ValueOf(diBean)
						valueOf.Elem().Field(i).Set(of)
					} else if diBeans, ok := b.container[beanName]; ok && diBeans != nil {
						var find bool
						for _, diBean := range diBeans {
							of := reflect.ValueOf(diBean)
							log.Println("beanName: " + beanName)
							log.Println("typeName: " + of.Type().Elem().Name())
							log.Println("fieldTypeName: " + field.Type.Name())
							if (of.Type().Elem().PkgPath() == field.Type.PkgPath() && of.Type().Elem().Name() == field.Type.Name()) || of.Type().Implements(field.Type) {
								valueOf.Elem().Field(i).Set(of)
								find = true
							}
						}
						if !find {
							log.Panicf("bean: %s dependcy: name: %s type: %s not found", name, beanName, field.Type.Name())
						}
					} else {
						log.Panicf("bean: %s dependcy: %s not found", name, beanName)
					}
				}
			}
		}
	}
	//遍历bean容器
	for name, bean := range b.typeContainer {
		//使用反射获取bean的值引用与类型引用
		valueOf := reflect.ValueOf(bean)
		typeOf := valueOf.Elem().Type()
		//遍历bean的属性,根据tag从容器中 获取对应对象进行注入
		for i := 0; i < typeOf.NumField(); i++ {
			field := typeOf.Field(i)
			if beanName, ok := field.Tag.Lookup("bean"); ok {
				if diBean, ok := b.typeContainer[field.Type]; ok && diBean != nil {
					of := reflect.ValueOf(diBean)
					valueOf.Elem().Field(i).Set(of)
				} else if diBeans, ok := b.container[beanName]; ok && diBeans != nil {
					var find bool
					for _, diBean := range diBeans {
						of := reflect.ValueOf(diBean)
						if (of.Type().Elem().PkgPath() == field.Type.PkgPath() && of.Type().Elem().Name() == field.Type.Name()) || of.Type().Implements(field.Type) {
							valueOf.Elem().Field(i).Set(of)
							find = true
						}
					}
					if !find {
						log.Panicf("bean: %s dependcy: name: %s type: %s not found", name, beanName, field.Type.Name())
					}
				} else {
					log.Panicf("bean: %s dependcy: %s not found", name, beanName)
				}
			}
		}
	}
}

func GetBean[T any](name string, b *BeanFactory) (T, bool) {
	beans, b2 := b.GetBean(name)
	if b2 {
		for _, bean := range beans {
			t, ok := bean.(T)
			return t, ok
		}
	}
	var t T
	return t, b2
}

func GetBeanByType[T any](t reflect.Type, b *BeanFactory) (T, bool) {
	byType, b2 := b.GetBeanByType(t)
	if b2 {
		tV, ok := byType.(T)
		return tV, ok
	}
	var tV T
	return tV, b2
}

func (b *BeanFactory) GetBean(name string) ([]any, bool) {
	bean, ok := b.container[name]
	if ok {
		return bean, ok
	}
	b.lock.Lock()
	defer b.lock.Unlock()
	var a []any
	return a, ok
}

func (b *BeanFactory) GetBeanByType(t reflect.Type) (any, bool) {
	bean, ok := b.typeContainer[t]
	if ok {
		return bean, ok
	}
	b.lock.Lock()
	defer b.lock.Unlock()
	var a any
	return a, ok
}
